home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cmdline.lha / cmdline / src / lib / private.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-13  |  19.5 KB  |  647 lines

  1. //------------------------------------------------------------------------
  2. // ^FILE: private.c - private/protected functions used by the CmdLine library
  3. //
  4. // ^DESCRIPTION:
  5. //  This file implements functions that are for the exclusive use of
  6. //  the CmdLine library.  The following functions are implemented:
  7. //
  8. //      ck_need_val()  --  see if we left an argument without a value
  9. //      handle_arg()   --  compile the string value of an argument
  10. //      syntax()       --  find out the desired syntax for usage messages
  11. //      missing_args() --  check for missing required arguments
  12. //      opt_match()    --  match an option
  13. //      kwd_match()    --  match a keyword
  14. //      pos_match()    --  match a positional parameter
  15. //
  16. // ^HISTORY:
  17. //    01/09/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  18. //
  19. //    03/03/93    Brad Appleton    <brad@ssd.csd.harris.com>
  20. //    - Added exit_handler() and quit() member-functions to CmdLine
  21. //-^^---------------------------------------------------------------------
  22.  
  23. #include <iostream.h>
  24. #include <strstream.h>
  25. #include <fstream.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <ctype.h>
  29.  
  30. extern "C" {
  31.   int  isatty(int fd);
  32.  
  33. #ifdef GNU_READLINE
  34. # include <readline.h>
  35. #endif
  36.  
  37. }
  38.  
  39. #ifndef GNU_READLINE
  40. # ifdef unix
  41. #  include <malloc.h>
  42. # else
  43.    extern "C" void * malloc(size_t);
  44.    extern "C" void   free(void *);
  45. # endif
  46. #endif
  47.  
  48.  
  49. #include "cmdline.h"
  50. #include "states.h"
  51. #include "arglist.h"
  52.  
  53.  
  54. // Need a portable version of tolower
  55. //
  56. //   NOTE:: I would make this inline except that cfront refuses
  57. //          to inline it because it is used twice in expressions
  58. //
  59. #define TO_LOWER(c)  ((isupper(c)) ? tolower(c) : c)
  60.  
  61. #ifdef vms
  62. #  define  getenv  getsym
  63.    extern  const char * getsym(const char *);
  64. #endif
  65.  
  66. //-------
  67. // ^FUNCTION: CmdLine::handle_arg - compile the string value of an argument
  68. //
  69. // ^SYNOPSIS:
  70. //    extern int CmdLine::handle_arg(cmdarg, arg);
  71. //
  72. // ^PARAMETERS:
  73. //    CmdArg * cmdarg;
  74. //    -- the matched argument whose value is to be "handled"
  75. //
  76. //    const char * & arg;
  77. //    -- the string value for the argument (from the command-line).
  78. //       upon exit, this will be NULL (if all of "arg" was used) or will
  79. //       point to the first character or "arg" that was not used by the
  80. //       argument's "compile" function.
  81. //
  82. // ^DESCRIPTION:
  83. //    After we have matched an argument on the command-line to an argument
  84. //    in the "cmd" object, we need to "handle" the value supplied for that
  85. //    argument. This entails updating the state of the argument and calling
  86. //    its "compile" function as well as updating the state of the command.
  87. //
  88. // ^REQUIREMENTS:
  89. //    None that weren't covered in the PARAMETERS section.
  90. //
  91. // ^SIDE-EFFECTS:
  92. //    - modifies the value pointed to by "arg"
  93. //    - prints a message on stderr if "arg" is invalid and QUIET is NOT set.
  94. //    - modifies the state of "cmd".
  95. //    - modifies the "value" and "flags" of "cmdarg".
  96. //
  97. // ^RETURN-VALUE:
  98. //    The value returned by calling the "compile" function associated
  99. //    with the argument "cmdarg".
  100. //
  101. // ^ALGORITHM:
  102. //    - if this is a cmdargUsage argument then print usage and call quit()
  103. //    - call the operator() of "cmdarg" and save the result.
  104. //    - if the above call returned SUCCESS then set the GIVEN and VALGIVEN
  105. //      flags of the argument.
  106. //    - update the parse_state of "cmd" if we were waiting for this value.
  107. //    - if "cmdarg" corresponds to a LIST then set things up so that succeeding
  108. //      arguments will be values for this "cmdarg"'s list.
  109. //-^^----
  110. int
  111. CmdLine::handle_arg(CmdArg * cmdarg, const char * & arg)
  112. {
  113.    ++cmd_nargs_parsed;  // update the number of parsed args
  114.  
  115.    // call the argument compiler
  116.    const char * save_arg = arg ;  // just in case someone forgets to set it
  117.    int  bad_val = (*cmdarg)(arg, *this);
  118.    if (! bad_val) {
  119.       cmdarg->set(CmdArg::GIVEN) ;
  120.       cmdarg->sequence(cmd_nargs_parsed) ;
  121.       if (arg != save_arg) {
  122.          cmdarg->set(CmdArg::VALGIVEN) ;
  123.       }
  124.    }
  125.  
  126.    // if we were waiting for a value - we just got it
  127.    if (arg != save_arg) {
  128.       if (cmdarg == cmd_matched_arg)  cmd_parse_state = cmd_START_STATE ;
  129.    }
  130.  
  131.    // if this is a list - optional values may follow the one given
  132.    if ((cmdarg->syntax() & CmdArg::isLIST) && (arg != save_arg)) {
  133.       cmd_matched_arg = cmdarg ;
  134.       cmd_parse_state = cmd_WANT_VAL ;
  135.    }
  136.  
  137.    return  bad_val ;
  138. }
  139.  
  140.  
  141. //-------
  142. // ^FUNCTION: CmdLine::ck_need_val - See if an argument needs a value
  143. //
  144. // ^SYNOPSIS:
  145. //    extern void CmdLine::ck_needval(void)
  146. //
  147. // ^PARAMETERS:
  148. //    NONE.
  149. //
  150. // ^DESCRIPTION:
  151. //    We parse command-lines using something akin to a deterministic
  152. //    finite state machine. Each argv[] element on the command-line is
  153. //    considered a single input to the machine and we keep track of an
  154. //    associated machine-state that tells us what to do next for a given
  155. //    input.
  156. //
  157. //    In this function, we are merely trying to query the "state" of the
  158. //    machine by asking it if it is expecting to see a value for an
  159. //    argument that was matched in a previous argv[] element.
  160. //
  161. //    It is assumed that this function is called only after it has already
  162. //    been determined that the current argv[] element is NOT an argument
  163. //    value.
  164. //
  165. // ^REQUIREMENTS:
  166. //
  167. // ^SIDE-EFFECTS:
  168. //    - updates the "state" of the command.
  169. //    - updates the "status" of the command.
  170. //    - modifies the last matched argument if it takes an optional value.
  171. //    - prints a message on stderr if cmd_QUIET is NOT set and we were
  172. //      expecting a required value.
  173. //
  174. // ^RETURN-VALUE:
  175. //    None.
  176. //
  177. // ^ALGORITHM:
  178. //    If we were expecting an optional value then
  179. //    - set the GIVEN flag of the last arg we matched (DO NOT set VALGIVEN).
  180. //    - call the compiler-function of the last-matched arg using NULL
  181. //      as the argument (unless the arg is a LIST and VALGIVEN is set).
  182. //    - reset the command-state
  183. //    Else if we were expecting a required value then
  184. //    - print a an error message if cmd_QUIET is not set
  185. //    - set the command-status to VAL_MISSING
  186. //    - reset the command-state
  187. //    Endif
  188. //-^^----
  189. void
  190. CmdLine::ck_need_val(void)
  191. {
  192.    const char * null_str = NULL;
  193.    if (cmd_parse_state == cmd_WANT_VAL) {
  194.       // argument was given but optional value was not
  195.       cmd_matched_arg->set(CmdArg::GIVEN) ;
  196.       if ((! (cmd_matched_arg->syntax() & CmdArg::isLIST)) ||
  197.           (! (cmd_matched_arg->flags()  & CmdArg::VALGIVEN))) {
  198.          (void) handle_arg(cmd_matched_arg, null_str) ;
  199.       }
  200.       cmd_parse_state = cmd_START_STATE ;
  201.    } else if (cmd_parse_state == cmd_NEED_VAL) {
  202.       // argument was given but required value was not
  203.       if (! (cmd_flags & QUIET)) {
  204.          arg_error("value required for", cmd_matched_arg) << "." << endl ;
  205.       }
  206.       cmd_status |= VAL_MISSING ;
  207.       cmd_parse_state = cmd_START_STATE ;
  208.    }
  209. }
  210.  
  211.  
  212. #ifndef GNU_READLINE
  213. //
  214. // readline() -- indigent person's version of the GNU readline() function
  215. //
  216.  
  217. #define PROMPT_BUFSIZE 256
  218.  
  219. static char *
  220. readline(const char * prompt)
  221. {
  222.    char * buf = (char *) ::malloc(PROMPT_BUFSIZE);
  223.    if (buf == NULL)  return  NULL ;
  224.    *buf = '\0';
  225.  
  226.    // prompt the user and collect input
  227.    cerr << prompt << flush ;
  228.    cin.getline(buf, PROMPT_BUFSIZE);
  229.  
  230.    return  buf ;
  231. }
  232. #endif // ! GNU_READLINE
  233.  
  234.  
  235. //-------
  236. // ^FUNCTION: CmdLine::prompt_user - prompt the user for a missing argument
  237. //
  238. // ^SYNOPSIS:
  239. //    unsigned CmdLine::prompt_user(cmdarg);
  240. //
  241. // ^PARAMETERS:
  242. //    CmdArg * cmdarg;
  243. //    -- the argument that we need to prompt for
  244. //
  245. // ^DESCRIPTION:
  246. //    If cin is connected to a terminal, then we will prompt the user
  247. //    for an argument corresponding to "cmdarg" and attempt to "compile" it
  248. //    into the desired internal format. The user only has one chance
  249. //    to get the "argument" right; we do not continue prompting if the
  250. //    value that was entered is invalid.
  251. //
  252. // ^REQUIREMENTS:
  253. //    "cmdarg" should be a REQUIRED argument that has already been determined
  254. //    to be missing from the command-line.
  255. //
  256. // ^SIDE-EFFECTS:
  257. //    - modifies the status of the command.
  258. //    - modifies "cmdarg".
  259. //    - prints a prompt on cerr and reads from cin
  260. //
  261. // ^RETURN-VALUE:
  262. //    0 if the argument was succesfully entered by the user,
  263. //    ARG_MISSING otherwise.
  264. //
  265. // ^ALGORITHM:
  266. //    - if cin is not a terminal return ARG_MISSING.
  267. //    - if "cmdarg" is a LIST, make sure we prompt the use once for each
  268. //      possible value in the list.
  269. //    - prompt the user for an argument and read the result.
  270. //    - if the user just typed <RETURN> return ARG_MISSING.
  271. //    - "handle" the value that was entered.
  272. //    - continue prompting if we are a LIST and a valid, non-empty,
  273. //      value was given
  274. //    - if an invalid value was given return ARG_MISSING
  275. //    - else return 0
  276. //-^^----
  277. unsigned
  278. CmdLine::prompt_user(CmdArg * cmdarg)
  279. {
  280.    // dont prompt if cin or cerr is not interactive
  281.    int fd = ((filebuf *)(cin.rdbuf()))->fd();
  282.    if (! ::isatty(fd))  return  ARG_MISSING ;
  283.  
  284.    fd = ((filebuf *)(cerr.rdbuf()))->fd();
  285.    if (! ::isatty(fd))  return  ARG_MISSING ;
  286.  
  287.    // if we have a list, need to prompt repeatedly
  288.    if (cmdarg->syntax() & CmdArg::isLIST) {
  289.       cerr << "Enter one " << cmdarg->value_name() << " per line "
  290.            << "(enter a blank-line to stop)." << endl ;
  291.    }
  292.    char prompt[256], * buf = NULL;
  293.    ostrstream  oss(prompt, sizeof(prompt));
  294.    oss << "\rEnter " << cmdarg->value_name() << ": " << ends ;
  295.    int  errs = 0, first = 1;
  296.    do {  // need repeated prompting for a LIST
  297.       if (buf)  ::free(buf);
  298.       buf = ::readline(prompt) ;
  299.       if (buf == NULL)  return  ARG_MISSING ;
  300.  
  301.       // make sure we read something!
  302.       if (! *buf) {
  303.          if (first) {
  304.             error() << "error - no " << cmdarg->value_name()
  305.                     << " given!" << endl ;
  306.             ++errs;
  307.          }
  308.          continue;
  309.       }
  310.  
  311. #ifdef GNU_READLINE
  312.       // add this line to the history list
  313.       ::add_history(buf);
  314. #endif
  315.  
  316.       // try to handle the value we read (remember - buf is temporary)
  317.       if (! errs) {
  318.          const char * arg = buf;
  319.          unsigned  save_cmd_flags = cmd_flags;
  320.          cmd_flags |= TEMP;
  321.          errs = handle_arg(cmdarg, arg);
  322.          if (errs) {
  323.             arg_error("bad value for", cmdarg) << "." << endl ;
  324.          }
  325.          cmd_flags = save_cmd_flags;
  326.       }
  327.  
  328.       first = 0;
  329.    } while (!errs && (cmdarg->syntax() & CmdArg::isLIST) &&  *buf);
  330.  
  331.    if (! errs)  cmdarg->set(CmdArg::VALSEP);
  332.  
  333.    if (buf)  ::free(buf);
  334.    return  (errs) ? ARG_MISSING : NO_ERROR ;
  335. }
  336.  
  337. //-------
  338. // ^FUNCTION: CmdLine::syntax - determine usage message syntax
  339. //
  340. // ^SYNOPSIS:
  341. //    CmdLine::CmdLineSyntax CmdLine::syntax(void);
  342. //
  343. // ^PARAMETERS:
  344. //
  345. // ^DESCRIPTION:
  346. //    One of the things we keep track of in the CmdLine object is whether
  347. //    options and/or keywords (long-options) were used on the command-line.
  348. //    If a command-line syntax error occurs and only options (keywords)
  349. //    were used then the usage message will only contain option (keyword)
  350. //    syntax. If BOTH were used or if usage was specifically requested via
  351. //    a cmdargUsage option (which we also keep track of) then we want the
  352. //    the usage message to contain the syntac for both options and keywords.
  353. //
  354. //    If neither options nor keywords were given (meaning only positional
  355. //    parameters were used) then we only use option-syntax (for brevity).
  356. //
  357. // ^REQUIREMENTS:
  358. //
  359. // ^SIDE-EFFECTS:
  360. //    None.
  361. //
  362. // ^RETURN-VALUE:
  363. //    The desired usage message syntax to use.
  364. //
  365. // ^ALGORITHM:
  366. //    Trivial.
  367. //-^^----
  368. CmdLine::CmdLineSyntax
  369. CmdLine::syntax(void) const
  370. {
  371.    if (cmd_flags & KWDS_ONLY) {
  372.       return  cmd_KWDS_ONLY;
  373.    } else if (cmd_flags & OPTS_ONLY) {
  374.       return  cmd_OPTS_ONLY;
  375.    } else if ((cmd_state & cmd_OPTIONS_USED) &&
  376.               (cmd_state & cmd_KEYWORDS_USED)) {
  377.       return  cmd_BOTH ;
  378.    } else if (cmd_state & cmd_KEYWORDS_USED) {
  379.       return  cmd_KWDS_ONLY ;
  380.    } else {
  381.       return  cmd_OPTS_ONLY ;
  382.    }
  383. }
  384.  
  385.  
  386. //-------
  387. // ^FUNCTION: CmdLine::missing_args - check for missing required arguments
  388. //
  389. // ^SYNOPSIS:
  390. //    unsigned CmdLine::missing_args(void);
  391. //
  392. // ^PARAMETERS:
  393. //
  394. // ^DESCRIPTION:
  395. //    This function checks to see if there is a required argument in the
  396. //    CmdLine object that was NOT specified on the command. If this is
  397. //    the case and PROMPT_USER is set (or $PROMPT_USER exists and is
  398. //    non-empty) then we attempt to prompt the user for the missing argument.
  399. //
  400. // ^REQUIREMENTS:
  401. //
  402. // ^SIDE-EFFECTS:
  403. //    - modifies the status of "cmd".
  404. //    - terminates execution by calling quit() if cmd_NOABORT is NOT
  405. //      set and a required argument (that was not properly supplied by
  406. //      the user) is not given.
  407. //    - prints on stderr if an argument is missing and cmd_QUIET is NOT set.
  408. //    - also has the side-effects of prompt_user() if we need to prompt
  409. //      the user for input.
  410. //
  411. // ^RETURN-VALUE:
  412. //    The current value of the (possibly modified) command status. This is a
  413. //    combination of bitmasks of type cmdline_flags_t defined in <cmdline.h>
  414. //
  415. // ^ALGORITHM:
  416. //    Foreach argument in cmd
  417. //       if argument is required and was not given
  418. //          if required, prompt for the missing argument
  419. //             if prompting was unsuccesful add ARG_MISSING to cmd-status
  420. //             endif
  421. //          else add ARG_MISSING to cmd-status
  422. //          endif
  423. //       endif
  424. //    endfor
  425. //    return the current cmd-status
  426. //-^^----
  427. unsigned
  428. CmdLine::missing_args(void)
  429. {
  430.    char buf[256];
  431.  
  432.    CmdArgListListIter  list_iter(cmd_args);
  433.    for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  434.       CmdArgListIter  iter(alist);
  435.       for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  436.          if (cmdarg->is_dummy())  continue;
  437.          if ((cmdarg->syntax() & CmdArg::isREQ) &&
  438.              (! (cmdarg->flags() & CmdArg::GIVEN)))
  439.          {
  440.             if (! (cmd_flags & QUIET)) {
  441.                fmt_arg(cmdarg,  buf, sizeof(buf), syntax(), TERSE_USAGE);
  442.                error() << buf << " required." << endl ;
  443.             }
  444.             if (cmd_status & ARG_MISSING) {
  445.                // user didnt supply the missing argument
  446.                return  cmd_status ;
  447.             } else if ((! (cmd_flags & NO_ABORT)) && cmd_status) {
  448.                // other problems
  449.                return  cmd_status ;
  450.             } else if (cmd_flags & PROMPT_USER) {
  451.                cmd_status |= prompt_user(cmdarg);
  452.             } else {
  453.                char * env = ::getenv("PROMPT_USER");
  454.                if (env && *env) {
  455.                   cmd_status |= prompt_user(cmdarg);
  456.                } else {
  457.                   cmd_status |= ARG_MISSING ;
  458.                }
  459.             }
  460.          } //if
  461.       } //for iter
  462.    } //for list_iter
  463.  
  464.    return  cmd_status ;
  465. }
  466.  
  467.  
  468. //-------
  469. // ^FUNCTION: CmdLine::opt_match - attempt to match on option
  470. //
  471. // ^SYNOPSIS:
  472. //    CmdArg * CmdLine::opt_match(optchar);
  473. //
  474. // ^PARAMETERS:
  475. //    char optchar;
  476. //    -- a possible option for "cmd"
  477. //
  478. // ^DESCRIPTION:
  479. //    If "cmd" has an argument that has "optchar" as a single-character
  480. //    option then this function will find and return that argument.
  481. //
  482. // ^REQUIREMENTS:
  483. //
  484. // ^SIDE-EFFECTS:
  485. //    None.
  486. //
  487. // ^RETURN-VALUE:
  488. //    If we find a match, then we return a pointer to its argdesc,
  489. //    otherwise we return NULL.
  490. //
  491. // ^ALGORITHM:
  492. //    Trivial.
  493. //-^^----
  494. CmdArg *
  495. CmdLine::opt_match(char optchar) const
  496. {
  497.    CmdArgListListIter  list_iter(cmd_args);
  498.    for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  499.       CmdArgListIter  iter(alist);
  500.       for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  501.          if (cmdarg->is_dummy())  continue;
  502.          if (optchar == cmdarg->char_name()) {
  503.             // exact match
  504.             return  cmdarg ;
  505.          } else if (cmd_flags & ANY_CASE_OPTS) {
  506.             // case-insensitive match
  507.             if (TO_LOWER(optchar) == TO_LOWER(cmdarg->char_name())) {
  508.                return  cmdarg ;
  509.             }
  510.          }
  511.       } //for iter
  512.    } //for list_iter
  513.    return  NULL ;
  514. }
  515.  
  516. //-------
  517. // ^FUNCTION: CmdLine::kwd_match - purpose
  518. //
  519. // ^SYNOPSIS:
  520. //    extern CmdArg * CmdLine::kwd_match(kwd, len, is_ambiguous, match_value);
  521. //
  522. // ^PARAMETERS:
  523. //    const char * kwd;
  524. //    -- a possible kewyord of "cmd"
  525. //
  526. //    int len;
  527. //    -- the number of character of "kwd" to consider (< 0 if all characters
  528. //       of "kwd" should be used).
  529. //
  530. //    int & is_ambiguous;
  531. //    -- upon return, the value pointed to is set to 1 if the keyword
  532. //       matches more than 1 keyword in "cmd"; Otherwise it is set to 0.
  533. //
  534. //    int match_value;
  535. //    -- if this is non-zero, then if a keyword_name is NULL use the 
  536. //       value_name instead.
  537. //
  538. // ^DESCRIPTION:
  539. //    If "cmd" has an argument that matches "kwd" as a kewyord
  540. //    then this function will find and return that argument.
  541. //
  542. // ^REQUIREMENTS:
  543. //
  544. // ^SIDE-EFFECTS:
  545. //    None.
  546. //
  547. // ^RETURN-VALUE:
  548. //    If we find a match, then we return a pointer to its argdesc,
  549. //    otherwise we return NULL.
  550. //
  551. // ^ALGORITHM:
  552. //    Set is_ambigous to 0.
  553. //    For each argument in cmd
  554. //       if argument's keyword-name matches kwd then
  555. //          if this was an exact match then return this argument
  556. //          else if we had a previous partial match of this argument then
  557. //             if argument is a default argument return the previous match
  558. //             else set is_ambiguous to 1 and return NULL
  559. //          else remember we had a partial match here and keep trying
  560. //          endif
  561. //       endif
  562. //    end for
  563. //    if we has a partial match and we get to here then it is NOT ambiguous do
  564. //       go ahead and return the argument we matched.
  565. //-^^----
  566. CmdArg *
  567. CmdLine::kwd_match(const char * kwd,
  568.                    int          len,
  569.                    int &        is_ambiguous,
  570.                    int          match_value) const
  571. {
  572.    CmdArg * matched = NULL;
  573.  
  574.    is_ambiguous = 0 ;
  575.  
  576.    CmdArgListListIter  list_iter(cmd_args);
  577.    for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  578.       CmdArgListIter  iter(alist);
  579.       for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  580.          if (cmdarg->is_dummy())  continue;
  581.  
  582.          // attempt to match this keyword
  583.          strmatch_t  result ;
  584.          const char * source = cmdarg->keyword_name();
  585.          if (source && *source) {
  586.             result = strmatch(source, kwd, len) ;
  587.          } else if (match_value) {
  588.             result = strmatch(cmdarg->value_name(), kwd, len) ;
  589.          }
  590.  
  591.          if (result == str_EXACT) {
  592.             return  cmdarg ;
  593.          } else if (result == str_PARTIAL) {
  594.             if (matched) {
  595.                is_ambiguous = 1 ;
  596.                return  NULL ;  // ambiguous keyword
  597.             }
  598.             matched = cmdarg ;  // we matched this one
  599.          }
  600.       } //for iter
  601.       if (matched) break;
  602.    } //for list_iter
  603.    return  matched ;
  604. }
  605.  
  606. //-------
  607. // ^FUNCTION: CmdLine::pos_match - match a positional argument
  608. //
  609. // ^SYNOPSIS:
  610. //    CmdArg * CmdLine::pos_match(void)
  611. //
  612. // ^PARAMETERS:
  613. //
  614. // ^DESCRIPTION:
  615. //    If "cmd" has an positional argument that has not yet been given
  616. //    then this function will find and return the first such argument.
  617. //
  618. // ^REQUIREMENTS:
  619. //
  620. // ^SIDE-EFFECTS:
  621. //    None.
  622. //
  623. // ^RETURN-VALUE:
  624. //    If we find a match, then we return a pointer to its argument,
  625. //    otherwise we return NULL.
  626. //
  627. // ^ALGORITHM:
  628. //    Trivial.
  629. //-^^----
  630. CmdArg *
  631. CmdLine::pos_match(void) const
  632. {
  633.    CmdArgListListIter  list_iter(cmd_args);
  634.    for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  635.       CmdArgListIter  iter(alist);
  636.       for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  637.          if (cmdarg->is_dummy())  continue;
  638.          if ((cmdarg->syntax() & CmdArg::isPOS) &&
  639.              (! (cmdarg->flags() & CmdArg::GIVEN)))
  640.          {
  641.             return  cmdarg ;
  642.          }
  643.       } //for iter
  644.    } //for list_iter
  645.    return  NULL ;
  646. }
  647.